//
//  JSNetworking.m
//  JigSaw
//
//  Created by Slim Wang on 15/3/11.
//  Copyright (c) 2015年 LITB. All rights reserved.
//

#import "JSNetworking.h"
#import "AFNetworking.h"
#import "JSHttpRequest.h"

#import <ReactiveCocoa/ReactiveCocoa.h>
@interface JSNetworking ()

@property(nonatomic, strong)AFHTTPRequestOperationManager* httpManager;

@end

@implementation JSNetworking

MACRO_SHARED_INSTANCE_IMPLEMENTATION(JSNetworking);
- (instancetype)init
{
    self = [super init];
    if (self) {
        self.httpManager = [[AFHTTPRequestOperationManager alloc] init];
        self.httpManager.requestSerializer = [AFJSONRequestSerializer serializer];
        self.httpManager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/html", @"text/plain", @"application/json", @"text/javascript", nil];
    }
    return self;
}

- (RACSignal *)rac_signalForHttpGET:(JSHttpRequest *)request
{
    [self prepareToSendRequest:request];
    
    NSString * urlString = [request url];
    NSDictionary * parameters = [request toParameters];
    
    @weakify(self);
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        JSLog(@"\n\n====================>\nGET FOR URL:\n%@ \n\nPARAMETERS:\n%@\n\n", urlString, parameters);
        @strongify(self);
        [self.httpManager GET:urlString
                   parameters:parameters
                      success:^(AFHTTPRequestOperation *operation, id responseObject)
         {
             JSLog(@"\n\n<====================\nRecevied RESPONSE:\n%@\nFOR URL: \n%@\n\n", responseObject, operation.request.URL);
             id object = [request onResponse:responseObject];
             [subscriber sendNext:RACTuplePack(operation, object, responseObject)];
             [subscriber sendCompleted];
         } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
             JSLog(@"\n\n<====================\nRecevied ERROR ( %@ ) \n ( %@)\n\n for url: { %@ }\n\n",
                   error, operation.responseString, operation.request.URL);
             [subscriber sendError:error];
         }];
        return [RACDisposable disposableWithBlock:^{
            // nothing
        }];
    }];
}

- (RACSignal *)rac_signalForHttpPOST:(JSHttpRequest *)request;
{
    [self prepareToSendRequest:request];
    
    NSString * urlString = [request url];
    NSDictionary * parameters = [request toParameters];
    
    @weakify(self);
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        JSLog(@"\n\n====================>\nPOST FOR URL:\n%@ \n\nPARAMETERS:\n%@\n\n", urlString, parameters);
        @strongify(self);
        [self.httpManager POST:urlString
                    parameters:parameters
                       success:^(AFHTTPRequestOperation *operation, id responseObject)
         {
             JSLog(@"\n\n<====================\nRecevied RESPONSE:\n%@\nFOR URL: \n%@\n\n", responseObject, operation.request.URL);
             id object = [request onResponse:responseObject];
             [subscriber sendNext:RACTuplePack(operation, object, responseObject)];
             [subscriber sendCompleted];
         } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
             JSLog(@"\n\n<====================\nRecevied ERROR ( %@ ) \n ( %@)\n\n for url: { %@ }\n\n",
                   error, operation.responseString, operation.request.URL);
             [subscriber sendError:error];
         }];
        return [RACDisposable disposableWithBlock:^{
            // nothing
        }];
    }];
}

- (RACSignal *)rac_signalForHttpPOSTWithoutJson:(NSString *)URLString
                                     parameters:(NSDictionary *)parameters
{
    SAFE_PREFORM_SELECTOR_WITH_OBJECT(self.delegate, @selector(willSendRequest:), URLString);
    
    @weakify(self);
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        @strongify(self);
        self.httpManager.requestSerializer = [AFHTTPRequestSerializer serializer];
        [self.httpManager POST:URLString parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
            [subscriber sendNext:RACTuplePack(operation, responseObject)];
            [subscriber sendCompleted];
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            [subscriber sendError:error];
        }];
        return [RACDisposable disposableWithBlock:^{
            // nothing
        }];
    }];
}

- (RACSignal *)rac_signalForHttpPOST:(JSHttpRequest *)request
                            filePath:(NSURL *)filePath
                                name:(NSString *)name
                            fileName:(NSString *)fileName
                            mimeType:(NSString *)mimeType;
{
    [self prepareToSendRequest:request];
    
    NSString * urlString = [request url];
    NSDictionary * parameters = [request toParameters];
    
    @weakify(self);
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        @strongify(self);
        JSLog(@"\n\n====================>\nPOST MIMETYPE:%@ FOR URL:\n%@ \n\nPARAMETERS:\n%@\n\nFILE_PATH:%@",
              mimeType, urlString, parameters, filePath.relativeString);
        [self.httpManager POST:urlString parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
            [formData appendPartWithFileURL:filePath name:name fileName:fileName mimeType:mimeType error:nil];
        } success:^(AFHTTPRequestOperation *operation, id responseObject) {
            JSLog(@"\n\n<====================\nRecevied RESPONSE:\n%@\nFOR URL: \n%@\n\n", responseObject, operation.request.URL);
            id object = [request onResponse:responseObject];
            [subscriber sendNext:RACTuplePack(operation, object, responseObject)];
            [subscriber sendCompleted];
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            JSLog(@"\n\n<====================\nRecevied ERROR ( %@ ) \n ( %@)\n\n for url: { %@ }\n\n", error, operation.responseString, operation.request.URL);
            [subscriber sendError:error];
        }];
        return [RACDisposable disposableWithBlock:^{
            // nothing
        }];
    }];
}

- (RACSignal *)rac_signalForHttpPOST:(JSHttpRequest *)request
                            fileData:(NSData *)fileData
                                name:(NSString *)name
                            fileName:(NSString *)fileName
                            mimeType:(NSString *)mimeType;
{
    [self prepareToSendRequest:request];
    
    NSString * urlString = [request url];
    NSDictionary * parameters = [request toParameters];
    
    @weakify(self);
    return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        @strongify(self);
        JSLog(@"\n\n====================>\nPOST FILE DATA WITH MIMETYPE:%@ FOR URL:\n%@ \n\nPARAMETERS:\n%@\n\n", mimeType, urlString, parameters);
        [self.httpManager POST:urlString parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
            [formData appendPartWithFileData:fileData name:name fileName:fileName mimeType:mimeType];
        } success:^(AFHTTPRequestOperation *operation, id responseObject) {
            JSLog(@"\n\n<====================\nRecevied RESPONSE:\n%@\nFOR URL: \n%@\n\n", responseObject, operation.request.URL);
            id object = [request onResponse:responseObject];
            [subscriber sendNext:RACTuplePack(operation, object, responseObject)];
            [subscriber sendCompleted];
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            JSLog(@"\n\n<====================\nRecevied ERROR ( %@ ) \n ( %@)\n\n for url: { %@ }\n\n", error, operation.responseString, operation.request.URL);
            [subscriber sendError:error];
        }];
        return [RACDisposable disposableWithBlock:^{
            // nothing
        }];
    }];
}

#pragma mark - Private

- (void)prepareToSendRequest:(JSHttpRequest *)request
{
    [self checkRequestHeaderFields:request];
    
    SAFE_PREFORM_SELECTOR_WITH_OBJECT(self.delegate, @selector(willSendRequest:), [request url]);
}

- (void)checkRequestHeaderFields:(JSHttpRequest *)request
{
    if ([request requestHeaders].count > 0) {
        [[request requestHeaders] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
            [self.httpManager.requestSerializer setValue:obj forHTTPHeaderField:key];
        }];
    }
}

@end
